home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 2000 February
/
Macworld (2000-02).dmg
/
Updaters
/
WhiteCap 3.2.2.sea
/
WhiteCap 3.2.2
/
WhiteCap Source
/
WhiteCap.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1999-10-29
|
24KB
|
1,067 lines
#include "WhiteCap.h"
#include "EgOSUtils.h"
#if EG_MAC
#include <Menus.h>
#include <Windows.h>
#include <Palettes.h>
#if MACAMP
#include "MacAMP_Visual.h"
extern VPInfoBlock gPlugInfo;
#endif
#if SOUNDJAM
#include "VisFramework.h"
#endif
#include "CEgFileSpec.h"
#include "Sample.h"
#include "CEgIOFile.h"
#define __setupPort GDHandle saveDev; \
GrafPtr savePort; \
::GetGWorld( (GWorldPtr*)(&savePort), &saveDev ); \
::SetPort( mOSPort );
#define __restorePort ::SetGWorld( (GWorldPtr)(savePort), saveDev );
#endif
#if EG_WIN
#define __setupPort
#define __restorePort
#include "RectUtils.h"
#include "vis.h"
extern winampVisModule gWCModule;
#endif
WhiteCap::WhiteCap( CEgFileSpec& inPluginsFolder, void* inRefCon ) :
mPrefs( "WhiteCap Preferences", true ),
mConfigs( cNoDuplicates_CaseInsensitive, cSortLowToHigh) {
CEgFileSpec spec;
UtilStr name, str;
mPrefs.Load();
if ( mPrefs.GetPref( 'Vers' ) != WHITECAP_COMPAT_VERSION ) {
mMagScale = 1;
mTransitionLo = 5;
mTransitionHi = 22;
mSlideShowInterval = 15000; // Factory: 15 secs per config
mScrnSaverDelay = -1 * 60000.0; // Factory: screen saver mode disabled
mPrefs.SetPref( 'Vers', WHITECAP_COMPAT_VERSION );
mShwT_Pref = 0x3;
mBorderlessWind = 0;
mHandleKeys = 1;
mCaptureMode = 0;
}
else {
mMagScale = mPrefs.GetPref( 'MScl' ) / 1000.0;
mTransitionLo = mPrefs.GetPref( 'TrLo' );
mTransitionHi = mPrefs.GetPref( 'TrHi' );
mSlideShowInterval = mPrefs.GetPref( 'Slde' ) * 1000.0;
mScrnSaverDelay = mPrefs.GetPref( 'SSvr' ) * 1000.0 * 60.0;
mShwT_Pref = mPrefs.GetPref( 'ShwT' );
mBorderlessWind = mPrefs.GetPref( 'NoBo' );
mHandleKeys = mPrefs.GetPref( 'Kybd' );
mCaptureMode = 0; //mPrefs.GetPref( 'Capt' );
}
mRefCon = inRefCon;
mInSlideShowMode = true;
mAtFullScreen = false;
mOSPort = NULL;
mNumWorlds = 0;
mFrameCount = 0;
mFrameCountStart =
mLastKeyPollTime =
mLastActiveTime =
mLastRecordTime = EgOSUtils::CurTimeMS();
mCurConfigNum = -1;
mNextShapeChange = 0x7FFFFFFF;
mFramesPer10Secs = 400;
mDoingSetPortWin = false;
mMouseWillAwaken = false;
mBltEntireWindow = false;
// Make the first slide show happen quickly
if ( mSlideShowInterval > 0 )
mNextShapeChange = mFrameCountStart + 10000;
BuildConfigList( inPluginsFolder );
#if EG_MAC
// If ctrl and option key held down, enter capture mode...
//mCaptureMode = true;
#endif
// Create capture data path if we're in capture mode
if ( mCaptureMode ) {
spec.AssignPathName( "WhiteCap Capture" );
spec.SetType( cWC_CaptureType );
mDumpFile.open( &spec );
mDumpFile.PutLong( cWhiteCapID );
mDumpFile.PutLong( WHITECAP_COMPAT_VERSION );
mDumpFile.PutLong( NUM_SAMPLE_BINS );
}
for ( int i = 0; i < NUM_SAMPLE_BINS; i++ )
mSample[ i ] = 0;
}
WhiteCap::~WhiteCap() {
SetFullScreen( false );
// Rewrite the prefs to disk...
mPrefs.SetPref( 'Slde', mSlideShowInterval / 1000.0 );
mPrefs.SetPref( 'SSvr', mScrnSaverDelay / 60000.0 );
mPrefs.SetPref( 'TrHi', mTransitionHi );
mPrefs.SetPref( 'TrLo', mTransitionLo );
mPrefs.SetPref( 'MScl', mMagScale * 1000 );
mPrefs.SetPref( 'ShwT', mShwT_Pref );
mPrefs.SetPref( 'NoBo', mBorderlessWind );
mPrefs.SetPref( 'Kybd', mHandleKeys );
mPrefs.SetPref( 'Capt', mCaptureMode );
#if MACAMP || WINAMP
Rect r;
#if MACAMP
GetWinRect( r );
#else
// Very annoying: in Win32, the call to GetWindowRect() is returning garbage in ~WhiteCap(), so just
// forget about saving the window position for now in windows :_(
//GetWinRect( r );
r = mWinRectHolder; // Just use a recent rect for now
#endif
mPrefs.SetPref( 'wTop', r.top );
mPrefs.SetPref( 'wLft', r.left );
mPrefs.SetPref( 'wBot', r.bottom );
mPrefs.SetPref( 'wRgt', r.right );
#endif
mPrefs.Store();
// Delete all the existing worlds
for ( int i = 0; i < mNumWorlds; i++ )
delete mWorld[ i ];
}
bool WhiteCap::PtInTitle( Point inPt ) {
int i;
Rect r;
GetWinRect( r );
inPt.v -= r.top;
inPt.h -= r.left;
for ( i = 0; i < mNumWorlds; i++ ) {
if ( ::PtInRect( inPt, &mWorld[ i ] -> mTitleRect ) )
return true;
}
return false;
}
void WhiteCap::SelectConfig() {
long i, sel;
Point pt;
UtilStr name;
EgOSUtils::GetMouse( pt );
// If we're in full screen mode, show the mouse ptr
if ( mAtFullScreen )
EgOSUtils::ShowCursor();
#if EG_MAC
MenuHandle menu;
__setupPort
// If we found a world, show a popup menu to select from the configs
menu = ::NewMenu( 123, "\p " );
// Add the stard slideshow item
::AppendMenu( menu, "\p " );
::SetMenuItemText( menu, 1, "\p(Start Slide Show)" );
if ( mInSlideShowMode )
::DisableItem( menu, 1 );
for ( i = 1; mConfigs.FetchSpecName( i, name ); i++ ) {
::AppendMenu( menu, "\p " );
::SetMenuItemText( menu, i + 1, name.getPasStr() );
}
::CheckItem( menu, mCurConfigNum + 1, true );
::InsertMenu( menu, -1 );
sel = ::PopUpMenuSelect( menu, pt.v - 6, pt.h, mCurConfigNum + 1 );
::DeleteMenu( 123 );
::DisposeMenu( menu );
sel = ( sel & 0xFFFF0000 ) ? (sel & 0xFFFF) : 0;
#endif
#if EG_WIN
long flags;
HMENU myMenu = ::CreatePopupMenu();
// Add item to start slideshow
flags = MF_STRING;
if ( mInSlideShowMode )
flags |= MF_GRAYED;
else
flags |= MF_ENABLED;
::AppendMenu( myMenu, flags, 1, "(Start Slide Show)" );
for ( i = 1; mConfigs.FetchSpecName( i, name ); i++ ) {
flags = MF_ENABLED | MF_STRING;
// Split up the menu if it's big...
if ( i % 35 == 0 )
flags |= MF_MENUBARBREAK;
// Check the config that's the current/displayed config
if ( mCurConfigNum == i )
flags |= MF_CHECKED;
::AppendMenu( myMenu, flags, i + 1, name.getCStr() );
}
sel = ::TrackPopupMenuEx( myMenu, TPM_RETURNCMD, pt.h, pt.v, mOSPort, NULL );
::DestroyMenu( myMenu );
if ( mAtFullScreen )
::SetCapture( mOSPort );
#endif
if ( sel > 0 ) {
if ( sel == 1 )
EnableSlideShow();
else if ( sel >= 1 ) {
LoadConfig( sel - 1, EgOSUtils::CurTimeMS() );
mInSlideShowMode = false;
}
}
__restorePort
}
void WhiteCap::EnableSlideShow() {
mInSlideShowMode = true;
mNextShapeChange = mLastRecordTime;
mConfigPlayList.Randomize();
}
void WhiteCap::SetFullScreen( bool inFullScreen ) {
// If we're in capture mode, don't allow fullscreen -- it'd be pointless
if ( mCaptureMode )
inFullScreen = false;
#if SOUNDJAM
VisHandlerData* handlerData = (VisHandlerData*) mRefCon;
if ( handlerData ) {
if ( mAtFullScreen != inFullScreen ) {
if ( PlayerSetFullScreen(handlerData->appCookie, handlerData->playerProc, inFullScreen) == noErr)
mAtFullScreen = inFullScreen;
}
}
#else
bool ok;
int dispNum;
Point size;
if ( inFullScreen && ! mAtFullScreen ) {
if ( PixPort::FullscreenAvail() ) {
__setupPort
// Update the positon of our win
GetWinRect( mWinRectHolder );
dispNum = PixPort::GetOwningDisplay( *((Point*) &mWinRectHolder) );
#if MACAMP
if ( gPlugInfo.ma -> EnterFullScreen )
gPlugInfo.ma -> EnterFullScreen( 'XXXX' /*cPluginAuthor*/, cWhiteCapID );
::HideWindow( mOSPort );
#endif
#if WINAMP
::ShowWindow( gWCModule.hwndParent, SW_HIDE | SW_MINIMIZE );
#endif
// Put in pref wheather to try 32 before 16 bit color?
ok = mPort.InitFullscreen( dispNum, size, mOSPort );
if ( ok ) {
mDispRect.left = 0;
mDispRect.top = 0;
mDispRect.right = size.h;
mDispRect.bottom = size.v;
ResizeWorlds();
mAtFullScreen = true;
mFullscreenStartTime = mLastRecordTime;
// If we don't expire them, there'll be an ugly gap for the time it took to go fullscreen
for ( int i = 0; i < mNumWorlds; i++ )
mWorld[ i ] -> ExpireSamples();
}
else {
#if MACAMP
if ( gPlugInfo.ma -> ExitFullScreen )
gPlugInfo.ma -> ExitFullScreen();
::ShowWindow( mOSPort );
#endif
#if WINAMP
::ShowWindow( gWCModule.hwndParent, SW_SHOWNORMAL );
#endif
}
__restorePort
} }
else if ( ! inFullScreen && mAtFullScreen ) {
#if MACAMP
if ( gPlugInfo.ma -> ExitFullScreen )
gPlugInfo.ma -> ExitFullScreen();
#endif
// Restore the window
mPort.Deactivate();
__setupPort
SetWinPort( mOSPort, &mWinRectHolder );
__restorePort
mLastMousePt.h -= 55;
mAtFullScreen = false;
#if WINAMP
::ShowWindow( gWCModule.hwndParent, SW_SHOWNORMAL );
#endif
}
#endif
if ( inFullScreen ) {
// Changing the port (and the resolution) may change the mouse cords
EgOSUtils::GetMouse( mLastMousePt );
// Default: mouse movement will not exit fullscreen mode
mMouseWillAwaken = false;
}
#if EG_MAC
::FlushEvents( 0xFFFF, 0 );
#endif
}
void WhiteCap::GetWinRect( Rect& outRect ) {
if ( mOSPort ) {
#if EG_MAC
outRect = (**(((CGrafPtr) mOSPort)->portPixMap)).bounds;
outRect.left *= -1;
outRect.top *= -1;
outRect.right = outRect.left + mOSPort -> portRect.right;
outRect.bottom = outRect.top + mOSPort -> portRect.bottom;
#elif EG_WIN
RECT wr;
::GetWindowRect( mOSPort, &wr );
outRect.left = wr.left;
outRect.top = wr.top;
outRect.right = wr.right;
outRect.bottom = wr.bottom;
#endif
}
else
SetRect( &outRect, 0, 0, 0, 0 );
}
void WhiteCap::RecordSample( long inCurTime ) {
// Apply the global magnitude scale to the sample/soundbyte
for ( int i = 0; i < NUM_SAMPLE_BINS; i++ )
mSample[ i ] *= mMagScale;
// We'll need the 'current' time in Draw()
mLastRecordTime = inCurTime;
// Give the sample data to the window if we're not in capture mode
if ( ! mCaptureMode ) {
// Loop thru all the panes in the window
for ( int i = 0; i < mNumWorlds; i++ ) {
// Tell the world to take a new sound sample (if it wants)
mWorld[ i ] -> RecordSample( inCurTime, mSample );
} }
else {
mDumpFile.PutByte( CAPTURE_SAMPLE );
mDumpFile.PutLong( inCurTime );
mDumpFile.PutBlock( mSample, sizeof( float ) * NUM_SAMPLE_BINS );
}
}
bool WhiteCap::HandleKey( long inChar ) {
bool handled = false;
if ( mHandleKeys ) {
if ( inChar >= ' ' && inChar <= '~' ) {
mKeyBuf.Append( (char) inChar );
handled = true; }
else if ( inChar == 128 || inChar == 8 ) {
mKeyBuf.Keep( mKeyBuf.length() - 1 );
handled = true;
}
mLastKeyTime = mLastRecordTime;
}
return handled;
}
void WhiteCap::Draw() {
Rect r;
Point pt;
long i, time = mLastRecordTime;
bool kybdPress;
void* port;
// Check key-entered config
if ( mKeyBuf.length() ) {
// Process the kybd buffer only if we haven't gotten any typing in a while
if ( time > mLastKeyTime + 2500 ) {
// See if what was types is a command to WhiteCap (vs. a config name to switch to)
if ( mKeyBuf.compareTo( "slideshow", false ) == 0 ) {
if ( mInSlideShowMode )
mInSlideShowMode = false;
else
EnableSlideShow(); }
else {
// Look for a config that best matches what was typed. Use exact match if user didn't type a lot
if ( mKeyBuf.length() >= 4 )
i = mConfigs.FetchBestMatch( mKeyBuf );
else
i = mConfigs.Lookup( mKeyBuf );
if ( i > 0 ) {
LoadConfig( i, mLastRecordTime );
// Do a reshuffle if the user changes configs (to avoid repeated patterns)
if ( mInSlideShowMode )
mConfigPlayList.Randomize();
}
}
mKeyBuf.Wipe();
}
}
// Load a random waveshape every so often, and randomize things
if ( time > mNextShapeChange && mInSlideShowMode ) {
// Load the next config in the (randomized) config list...
i = mConfigPlayList.FindIndexOf( mCurConfigNum );
// Make a new play list if we've reached the end of the list...
if ( i >= mConfigPlayList.Count() ) {
mConfigPlayList.Randomize();
i = 0;
}
LoadConfig( mConfigPlayList.Fetch( i + 1 ), mLastRecordTime );
}
// Don't bother doing mouse or kybd poll if sceeen saver mode is disabled
if ( mScrnSaverDelay > 0 ) {
kybdPress = false;
#if EG_MAC
long pollDelay;
// Calc time till next kybd poll (Don't waste valuble time checking the kybd unless we've been idle a while)
if ( mAtFullScreen )
pollDelay = 600;
// Don't bother rapildly checking the kybd until we're really close to going into screen saver mode
else if ( time > mLastActiveTime + mScrnSaverDelay - 90000 )
pollDelay = ( mLastActiveTime + mScrnSaverDelay - time ) >> 7;
else
pollDelay = 10000;
// If it's time to poll the kybd...
if ( time > mLastKeyPollTime + pollDelay ) {
::GetKeys( mCurKeys );
mLastKeyPollTime = time;
// If the keys are pressed, 'move' the mouse (ie, cause the if-block a few lines from now to 'go'
if ( ( mCurKeys[0] != mPastKeys[0] ) ||
( mCurKeys[1] != mPastKeys[1] ) ||
( mCurKeys[2] != mPastKeys[2] ) ||
( mCurKeys[3] != mPastKeys[3] ) ) {
kybdPress = true;
mPastKeys[0] = mCurKeys[0];
mPastKeys[1] = mCurKeys[1];
mPastKeys[2] = mCurKeys[2];
mPastKeys[3] = mCurKeys[3];
}
}
#endif
// Check the mouse pos and record it as active if its been moved.
EgOSUtils::GetMouse( pt );
if ( pt.h != mLastMousePt.h || pt.v != mLastMousePt.v || kybdPress ) {
mLastMousePt = pt;
mLastActiveTime = time;
if ( mAtFullScreen && mMouseWillAwaken )
SetFullScreen( false );
}
// If we're elligible to enter fullscreen
if ( ! mAtFullScreen && time > mLastActiveTime + mScrnSaverDelay ) {
SetFullScreen( true );
mMouseWillAwaken = true;
}
}
__setupPort
// Tell the PixPort we're about to start accessing it big time
port = mPort.BeginFrame();
if ( ! port )
port = mOSPort;
if ( ! mCaptureMode ) {
// Loop thru all the panes in the window and the the whitecap wave thingy
for ( i = 0; i < mNumWorlds; i++ ) {
// Tell the world to update itself to the offscreen draw port
mWorld[ i ] -> Render( time, mPort, r );
// If we're doing a capture playback, we have to make the dirty rect the entire pane
if ( mBltEntireWindow )
r = *mWorld[ i ] -> PaneRect();
// If we're drawing to a window, draw it right away
if ( mPort.IsFullscreen() )
mPort.UnionDirtyRect( &r );
else
mPort.CopyBits( mOSPort, &r, &r );
}
// See if we want to draw the title...
bool drawTitle;
if ( mAtFullScreen )
drawTitle = ( mShwT_Pref & 0x1 ) != 0;
else
drawTitle = ( mShwT_Pref & 0x2 ) != 0;
if ( drawTitle ) {
// In the case we're using DrawSpocks, the cur port is the 'screen' port
#if MACAMP
if ( mPort.IsFullscreen() )
::GetPort( (GrafPtr*) &port );
#endif
#if WINAMP
if ( ! mAtFullScreen )
port = ::GetDC( mOSPort );
#endif
// For each pane/world, draw the title string...
for ( i = 0; i < mNumWorlds; i++ ) {
mWorld[ i ] -> DrawConfigName( port );
// In mac land, we may need to tell the port to refresh the given rect on the screen
#if EG_MAC
mPort.UnionDirtyRect( &mWorld[ i ] -> mTitleRect );
#endif
}
#if WINAMP
if ( ! mAtFullScreen )
::ReleaseDC( mOSPort, (HDC) port );
#endif
}
#if EG_MAC
// If the option key is down, show the frame rate
unsigned char km[16];
::GetKeys( (unsigned long*) km );
i = 58;
if ( ((km[ i >> 3 ] >> (i & 7)) & 1) != 0 ) {
// Calc frame rate, show the current computation for frames
if ( time - mFrameCountStart >= 1500 ) {
mFramesPer10Secs = 10000 * mFrameCount / ( time - mFrameCountStart );
mFrameRate.Assign( mFramesPer10Secs );
mFrameRate.Insert( mFrameRate.length() - 1, ".", 1 );
mFrameCountStart = time;
mFrameCount = 0;
}
mFrameCount++;
Rect r = { 0, 0, 20, 40 };
::EraseRect( &r );
::MoveTo( 5, 15 );
::DrawString( mFrameRate.getPasStr() );
if ( mPort.IsFullscreen() )
mPort.UnionDirtyRect( &r );
}
#endif
}
else {
#if EG_MAC
::MoveTo( 5, 20 );
::DrawString( "\pCapturing..." );
#endif
}
mPort.EndFrame();
__restorePort
}
#define ___max( a, b ) (( (a) > (b) ) ? (a) : (b))
#define ___maxSide( r ) (___max( r.right - r.left, r.bottom - r.top ))
void WhiteCap::SetWinPort( GrafPtr inWin, const Rect* inRect ) {
Rect r;
// mDoingSetPortWin == true is a signal that another thread is in SetWinPort()
if ( mDoingSetPortWin )
return;
mDoingSetPortWin = true;
if ( inRect )
r = *inRect;
// If an invalid win rect, fix it, you monkey!
if ( r.right - r.left < 20 || r.bottom - r.top < 20 || ! inRect ) {
r.top = mPrefs.GetPref( 'wTop' );
r.left = mPrefs.GetPref( 'wLft' );
r.right = mPrefs.GetPref( 'wRgt' );
r.bottom = mPrefs.GetPref( 'wBot' );
#if EG_MAC
// Invalidate the window if it's offscreen...
RgnHandle deskRgn = ::GetGrayRgn();
::SectRect( &(*deskRgn) -> rgnBBox, &r, &r );
#endif
}
// If no prefs avail (or an older version, use factory rect) or a bad win, hard code a size
if ( mPrefs.GetPref( 'Vers' ) != WHITECAP_COMPAT_VERSION || r.right - r.left < 20 || r.bottom - r.top < 20 ) {
r.top = 52;
r.left = 16;
r.right = 480;
r.bottom = 380;
}
long x = r.right - r.left;
long y = r.bottom - r.top;
// Make width a double-word multiple
r.right -= x % 4;
#if EG_MAC
::MoveWindow( inWin, r.left, r.top, true );
::SizeWindow( inWin, x, y, true );
::ShowWindow( inWin );
#else
RECT cr;
// Resize the window and find the rgn we have to work with
::MoveWindow( inWin, r.left, r.top, x, y, false );
::GetClientRect( inWin, &cr );
x = cr.right - cr.left;
y = cr.bottom - cr.top;
#endif
// The playpen for WhiteCap will be the entire window client rgn (what we'll give SetPort)
Rect portRect;
::SetRect( &portRect, 0, 0, x, y );
SetPort( inWin, portRect, false );
// Signal that this thread is done with SetPortWin()
mDoingSetPortWin = false;
}
void WhiteCap::SetPort( GrafPtr inPort, const Rect& inRect, bool inFullScreen ) {
long x = inRect.right - inRect.left;
long y = inRect.bottom - inRect.top;
mOSPort = inPort;
mPort.Init( x, y );
mDispRect = inRect;
mAtFullScreen = inFullScreen;
__setupPort
// If we're brand spankin new, show at least 1 config, you monkey
if ( mNumWorlds == 0 )
LoadConfig( mCurConfigNum, mLastRecordTime );
__restorePort
for ( int i = 0; i < mNumWorlds; i++ )
mWorld[ i ] -> ExpireSamples();
ResizeWorlds();
}
void WhiteCap::ResizeWorlds() {
Rect r;
long i, j, bestLen, cutLen, best;
// Resize the panes in this window...
mWorld[ 0 ] -> SetPaneRect( mDispRect );
for ( i = 1; i < mNumWorlds; i++ ) {
// Find the best world to cut in half
for ( bestLen = -1, j = 0; j < i; j++ ) {
cutLen = ___maxSide( (*mWorld[ j ] -> PaneRect()) );
if ( cutLen >= bestLen ) {
bestLen = cutLen;
best = j;
}
}
// Change the pane rect of both the unplaced world and the world that's about to get cut in half
r = *(mWorld[ best ] -> PaneRect());
if ( r.right - r.left == bestLen ) {
r.right -= bestLen / 2;
mWorld[ best ] -> SetPaneRect( r );
OffsetRect( &r, bestLen / 2, 0 );
mWorld[ i ] -> SetPaneRect( r ); }
else {
r.bottom -= bestLen / 2;
mWorld[ best ] -> SetPaneRect( r );
OffsetRect( &r, 0, bestLen / 2 );
mWorld[ i ] -> SetPaneRect( r );
}
}
}
void WhiteCap::RefreshRect( const Rect& inUpdate ) {
for ( int i = 0; i < mNumWorlds; i++ ) {
mWorld[ i ] -> RefreshRect( inUpdate );
}
}
void WhiteCap::LoadConfig( int inConfigNum, long inCurTime ) {
const CEgFileSpec* configSpec;
int i, exists;
long oldNumWorlds = mNumWorlds;
long transitionTime = EgOSUtils::Rnd( mTransitionLo * 1000, mTransitionHi * 1000 );
mNumWorlds = 0;
mCurConfigNum = -1;
// Don't bother initiating a config change if we're already running that config
if ( inConfigNum == mCurConfigNum )
return;
// Fetch the spec for our config file or folder
configSpec = mConfigs.FetchSpec( inConfigNum );
if ( configSpec ) {
// If we have a folder or file...
exists = configSpec -> Exists();
if ( exists == 2 ) {
CEgFileSpec spec;
bool startOver = true;
while ( EgOSUtils::GetNextFile( *configSpec, spec, startOver, false ) ) {
if ( mNumWorlds >= oldNumWorlds )
mWorld[ mNumWorlds ] = new WhiteCapWorld;
mWorld[ mNumWorlds ] -> Init( &spec, inCurTime, transitionTime );
mNumWorlds++;
startOver = false;
}
}
// Know what to put a check mark next to in the popup menu
mCurConfigNum = inConfigNum;
}
// If we're in capture, signal a config change...
if ( mCaptureMode ) {
UtilStr name;
if ( mConfigs.FetchSpecName( mCurConfigNum, name ) ) {
mDumpFile.PutByte( CAPTURE_CONFIG_CHANGE );
name.WriteTo( &mDumpFile );
}
}
// If it's only one config file or there's no spec specifed
if ( mNumWorlds == 0 ) {
mNumWorlds = 1;
if ( mNumWorlds > oldNumWorlds )
mWorld[ 0 ] = new WhiteCapWorld;
mWorld[ 0 ] -> Init( configSpec, inCurTime, transitionTime );
}
for ( i = mNumWorlds; i < oldNumWorlds; i++ )
delete mWorld[ i ];
// Set the time for when we load a random config automatically
mNextShapeChange = mLastRecordTime + mSlideShowInterval + transitionTime;
// If the cursor was spun, init it back to the ptr
EgOSUtils::ResetCursor();
// Make sure all WhiteCap's configs live happily inside the allowed draw area
ResizeWorlds();
// Very annoying: in Win32, the call to GetWindowRect() is returning garbage in ~WhiteCap(), so just
// forget about saving the window position for now in windows :_(
#if EG_WIN
if ( ! mAtFullScreen )
GetWinRect( mWinRectHolder );
#endif
if ( mAtFullScreen )
EgOSUtils::HideCursor();
}
void WhiteCap::BuildConfigList( CEgFileSpec& inPluginsFolder ) {
CEgFileSpec spec;
bool startOver = true;
int i;
while ( EgOSUtils::GetNextFile( inPluginsFolder, spec, startOver, false ) ) {
mConfigs.AddCopy( spec );
startOver = false;
}
startOver = true;
while ( EgOSUtils::GetNextFile( inPluginsFolder, spec, startOver, true ) ) {
mConfigs.AddCopy( spec );
startOver = false;
}
// Always have a item called (Default) in the config list
UtilStr def( "(Default)" );
spec.Assign( inPluginsFolder );
if ( ! mConfigs.Lookup( def ) ) {
spec.Rename( def );
mConfigs.AddCopy( spec );
}
mCurConfigNum = mConfigs.Lookup( def );
// Build a random config 'play' list
mConfigPlayList.RemoveAll();
for ( i = mConfigs.Count(); i > 0; i-- )
mConfigPlayList.Add( i );
mConfigPlayList.Randomize();
}
CEgErr WhiteCap::DoDump( CEgIStream* inStream, long inNumSampleBins, long inFPS ) {
CEgFileSpec spec;
long captureCode, t, frame, minNextTime;
long frameDelay = 1000 / inFPS;
UtilStr str;
CEgIOFile oFile;
CEgErr err;
frame = 0;
minNextTime = -1;
mHandleKeys = false;
mCaptureMode = false;
mBltEntireWindow = true;
spec.SetType( 'PICT' );
#if EG_MAC
PicHandle pic;
GrafPtr port;
::GetPort( &port );
::SetPort( mOSPort );
#endif
captureCode = inStream -> GetByte();
while ( inStream -> noErr() && err.noErr() && frame < 1050 ) {
switch ( captureCode ) {
case CAPTURE_SAMPLE:
// Mimic a legit sound sample being recorded
t = inStream -> GetLong();
inStream -> GetBlock( mSample, sizeof( float ) * NUM_SAMPLE_BINS );
if ( t < minNextTime )
break;
minNextTime += frameDelay;
RecordSample( t );
frame++;
// Generate the frame datapath
str.Assign( frame );
while ( str.length() < 4 )
str.Prepend( "0" );
str.Prepend( "WC." );
spec.AssignPathName( str.getCStr() );
oFile.open( &spec );
err = oFile;
#if EG_MAC
// Get the OS to script the frame
pic = ::OpenPicture( &mDispRect );
Draw();
::ClosePicture();
oFile.CEgOStream::skip( 512 );
oFile.PutBlock( *pic, ::GetHandleSize( (Handle) pic ) );
oFile.close();
::DrawPicture( pic, &mDispRect );
::KillPicture( pic );
#endif
break;
case CAPTURE_CONFIG_CHANGE:
// Mimic something entered from the kybd...
mKeyBuf.ReadFrom( inStream );
mLastKeyTime = mLastRecordTime - 1000000;
break;
}
captureCode = inStream -> GetByte();
EgOSUtils::SpinCursor();
}
#if EG_MAC
::SetPort( port );
#endif
// If any prefs were changed, don't save the changes
mPrefs.SetNotDirty();
return err;
}